/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 *
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_ui.htm
 *
 * Zhiqim UI is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

+(function(window, undefined)
{
/**************************************************/
//定义常用的对象，便于压缩文件，新增自定义标签
/**************************************************/
var document = window.document;
document.createElement("zcover");

/*************************************************************************************************/
//定义zhiqim/Z为一个空函数对象，用于1.命名空间使用，2.作为Z.Query的快捷方式，如果Z有冲突请使用zhiqim
/*************************************************************************************************/
var Z = window.Z = window.zhiqim = function(selector)
{
    return new Z.Query({selector:selector});
};

/**************************************************/
//定义zhiqim下的静态属性
/**************************************************/

Z.v  = "8.0.4";
Z.u  = undefined;
Z.d  = window.document;
Z.l  = window.location;
Z.n  = window.navigator;

Z.ua = Z.n.userAgent.toLowerCase();
Z.cp = "/";

/**************************************************/
//定义zhiqim下的静态常量
/**************************************************/

Z._D_    = "0123456789";
Z._LU_   = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Z._LL_   = "abcdefghijklmnopqrstuvwxyz";
Z._L_    = Z._LU_ + Z._LL_;

Z._DL_   = Z._D_ + Z._L_;
Z._DLL_  = Z._D_ + Z._LL_;
Z._DLU_  = Z._D_ + Z._LU_;

Z._DH_   = Z._D_ + "abcdefABCDEF";
Z._DHL_  = Z._D_ + "abcdef";
Z._DHU_  = Z._D_ + "ABCDEF";
Z._SYM_  = "._-`~!@#$%";

/**************************************************/
//定义zhiqim下的静态函数
/**************************************************/
Z.body = function()
{
    if (Z.d.body){
        return Z.d.body;
    }else{
        Z.alert("未初始化body，请在Z.onload之后调用！");
        throw "nobody";
    }
};

Z.param = function(name)
{//地址栏上的参数
    var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
    var r = Z.l.search.substr(1).match(reg);
    return (r == null)?null:unescape(r[2]);
};

Z.write = function(value)
{//输出到界面
    document.write(value);
};

Z.assert = function(require, exception, message)
{//断言，失败弹出告警并抛出异常
    if (!require)
    {
        Z.alert(message);
        throw exception;
    }
};

Z.evals = function(expression)
{//执行表达式脚本
    try{return eval('(' + expression + ')');}catch(e){return null;}
};

Z.encode = function(value)
{//编码
    return encodeURIComponent(value);
};

Z.decode = function(value)
{//解码
    return decodeURIComponent(value);
};

Z.parseFloat = function(value)
{//解析成浮点型
    return parseFloat(value);
};

Z.parseInt = function(value)
{//解析成整型
    return parseInt(value);
};

Z.loads = function(src, callback)
{//加载脚本文件
    var $script = document.createElement("script");
    $script.src = src;
    $script.onload = callback
    document.body.appendChild($script);
};

Z.alert = function(text, callback, param)
{//弹出告警，默认系统调用，支持后续覆盖
    alert(text);
    if (Z.T.isFunction(callback)){
        callback();
    }
};

Z.success = function(text, callback, param)
{//弹出成功
    param = param || {};
    param.type = "success";
    Z.alert(text, callback, param);
};

Z.failure = function(text, callback, param)
{//弹出失败
    param = param || {};
    param.type = "failure";
    Z.alert(text, callback, param);
};

Z.confirm = function(text, callback, param)
{//弹出询问，默认系统调用，支持后续覆盖
    if (confirm(text)){
        callback();
    }
};

Z.prompt = function(text, value, callback, param)
{//弹出修改值，默认系统调用，支持后续覆盖
    if (prompt(text, value)){
        callback();
    }
};

Z.copy = function(text, type)
{//复制，注意该方法要在用户事件中才有效，AJAX时使用同步
    if (!text){
        Z.alert("请输入要复制的文本");
        return;
    }

    if (!document.execCommand){
        Z.alert("当前浏览器不支持复制");
        return;
    }

    var $textarea = Z("<textarea class='z-hidden-fixed'></textarea>").appendTo("body");

    type = type || "text";
    if (type == "val")
        $textarea.val(text);
    else if (type == "html")
        $textarea.html(text);
    else
        $textarea.text(text);

    //选中文本域内容，执行复制命令，然后清除文本域
    $textarea.select();
    document.execCommand("copy");
    $textarea.remove();
};

Z.bind = function(f, $this)
{//返回一个新的函数，使得原函数this指向$this对象下执行
    if (!Z.bind.fs)
    {
        Z.bind.fs = [];
        Z.bind.ts = [];
        Z.bind.ns = [];
    }

    var ind = -1;
    Z.each(Z.bind.fs, function(_f, i)
    {
        if (_f !== f)
            return;

        if (Z.bind.ts[i] !== $this)
            return;

        //找到f和$this相同的则返回
        ind = i;return true;
    });

    if (ind == -1)
    {//未找到则新建一个函数
        ind = Z.bind.fs.length;
        Z.bind.fs[ind] = f;
        Z.bind.ts[ind] = $this;
        Z.bind.ns[ind] = function(){f.apply($this, arguments);};
    }

    return Z.bind.ns[ind];
};

Z.each = function(object, callback)
{//减化循环处理,默认this绑定到item上
    return Z.eachof(null, object, callback);
};

Z.eachof = function($this, object, callback)
{//减化循环处理，支持对字符串,数字,类数组和纯对象处理，=true表示中途退出循环，默认this绑定到传入的$this上，如果未传则绑定到item上

    if (!object || !Z.T.isFunction(callback))
        return;

    if (!Z.T.isLikeArray(object) && !Z.T.isPlainObject(object) && !Z.T.isString(object) && !Z.T.isNumber(object))
        return;

    //把参数放置到数组中,其中第一个不要
    var args = [];
    for (var a=0;a<arguments.length-1;a++)
    {
        args[a] = arguments[a+1];
    }

    //循环处理时，第1个参数为索引号，第二个参数为当前值，后面为用户传入的固定参数表
    if (Z.T.isString(object))
    {//字符串
        for (var i=0;i<object.length;i++)
        {
            args[0] = object.charAt(i);
            args[1] = i;
            if (callback.apply($this?$this:args[0], args))
                return true;//退出循环
        }
    }
    else if (Z.T.isNumber(object))
    {//数字
        for (var n=0;n<object;n++)
        {
            args[0] = n;
            args[1] = n;
            if (callback.apply($this?$this:args[0], args))
                return true;//退出循环
        }
    }
    else if (Z.T.isLikeArray(object))
    {//类数组
        for (var ind=0;ind<object.length;ind++)
        {
            args[0] = object[ind];
            args[1] = ind;
            if (callback.apply($this?$this:args[0], args))
                return true;//退出循环
        }
    }
    else
    {//纯对象
        for (var key in object)
        {
            if (!Z.O.isOwn(object, key))
                continue;//不是自己的属性不处理

            args[0] = object[key];
            args[1] = key;
            if (callback.apply($this?$this:args[0], args))
                return true;//退出循环
        }
    }
};

Z.clone = function(obj)
{//克隆一个新值
    if (Z.T.isNil(obj) || Z.T.isPrimitive(obj))
    {//空类型和基本类型直接赋值
        return obj;
    }

    if (Z.T.isPlainObject(obj))
    {//纯对象，拷贝属性
        var object = {};
        for (var key in obj){
            object[key] = Z.clone(obj[key]);
        }
        return object;
    }

    if (obj instanceof Z.HashMap)
    {//自定义的HashMap
        var map = new Z.HashMap();
        Z.each(obj.keySet(), function(key){
            map.put(key, obj.get(key));
        });
        return map;
    }
    //以下为五种宿主对象类型
    var type = Z.O.toString(obj);
    switch(type)
    {
        case "Function": return obj;
        case "Date": return new Date(obj);
        case "RegExp": return new RegExp(obj);
        case "Array":
        {
            var array = [];
            for (var i=0;i<obj.length;i++){
                array[i] = Z.clone(obj[i]);
            }
            return array;
        }
        default: return obj;
    }
};

Z.onload = function(f)
{//初始化后加载
    var args = [];//用于实参和形参位置对应
    for (var i=1;i<arguments.length;i++)
        args.push(arguments[i]);

    if (!Z.loader)
        Z.loader = new Z.Loader();

    if (Z.loader.isLoad)
        f.apply(document, args);
    else
        Z.loader.push(f, args);
};

Z.random = function(length, type)
{//随机生成一定长度的字符或数字
 //@param length 长度,
 //@param type 类型表名生成的随机字符串是字母数字(0或undefinde),数字(1),字母(2),大写字母(3),小写字母(4),大写字母和数字(5),小写字母和数字(6),大写十六进制(7),小写十六进制(8)

    //默认是数字+字母
    var send = Z._DL_;
        maxLength = 62;

    if (type && Z.V.isIntegerPositive(type))
    {//如果指定了type，则重新赋值
        switch (type)
        {
        case 1:
            maxLength = 10;
            send = Z._D_;
            break;
        case 2:
            maxLength = 52;
            send = Z._L_;
            break;
        case 3:
            maxLength = 26;
            send = Z._LU_;
            break;
        case 4:
            maxLength = 26;
            send = Z._LL_;
            break;
        case 5:
            maxLength = 36;
            send = Z._DLU_;
            break;
        case 6:
            maxLength = 36;
            send = Z._DLL_;
            break;
        case 7:
            maxLength = 16;
            send = Z._DHU_;
            break;
        case 8:
            maxLength = 16;
            send = Z._DHL_;
            break;
        case 9:
            maxLength = 10;
            send = Z._SYM_;
            break;
        }
    }

    var result = "";
    for (var i=0;i<length;i++)
    {
        result += send.charAt(Math.floor(Math.random() * maxLength));
    }

    return result;
};

Z.uuid = function()
{//通过随机数和当前时间生成唯一编号，格式：
 //XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
 //1、1-8位随机数
 //2、3段4长度的随机数
 //3、8位长度时间+4位随机数
    var uid = "", i = 0, j = 0;
    var HEX_LETTERS = Z._DHU_.split('');

    for (i=0;i<8;i++)
    {//前8位为0-F的随机数
        uid += HEX_LETTERS[Math.floor(Math.random() *  16)];
    }

    for (i=0;i<3;i++)
    {//三段3*4随机数
        for (j=0;j<4;j++)
        {
            uid += HEX_LETTERS[Math.floor(Math.random() *  16)];
        }
    }

    //最后12的前8位是时间戳，不足前补0
    var time = new Date().getTime();
    uid += ("0000000" + time.toString(16).toUpperCase()).substr(-8);

    for (i=0;i<4;i++)
    {//最后12的后4位随机数
        uid += HEX_LETTERS[Math.floor(Math.random() *  16)];
    }

    return uid;
};

Z.timer = function(speed, times, $this, process, complete)
{//定时任务
    if (!Z.T.isNumber(speed) || !Z.T.isNumber(times))
    {//速度和次数不是数值型不处理
        return;
    }

    var timer = null;
    if (times == -1)
    {//无穷执行
        timer = setInterval(stepNoEnd, speed);
    }
    else
    {//有次数限制
        timer = setInterval(stepHasEnd, speed);
    }

    function stepNoEnd()
    {
        if (process)
            process.call($this);
    }

    var curTimes = 0;
    function stepHasEnd()
    {
        curTimes += 1;
        if (curTimes >= times)
        {//定时器结束
            clearInterval(timer);
            if (complete)
                complete.call($this);
        }
        else
        {
            if (process)
                process.call($this, curTimes);
        }
    }

    return timer;
};

Z.rootPath = function(contextPath, path)
{//上下文件环境根环境为/，其他格式如/portal
    contextPath = contextPath || Z.cp;
    return ((contextPath == null || contextPath=="/")?"":contextPath) + (Z.S.startWith(path, "/")?"":"/") + path;
};

Z.textLineNum = function(text, width, fontSize, fontFamily, letterSpacing)
{//计算文本宽度，指定textarea无边框无滚动条，英文断词，通过固定行高滚动高度计算行数
    fontFamily = fontFamily || ('"微软雅黑","宋体",Arial,sans-serif');
    letterSpacing = letterSpacing || "normal";
    var $textarea = Z('<textarea class="z-fixed-tl0 zi-pd0 z-hidden z-bd-none z-overflow-hidden z-text-break z-lh50 z-h50">'
        + text + '</textarea>')
        .css("width", width).css("fontSize", fontSize).css("fontFamily", fontFamily).css("letterSpacing", letterSpacing)
        .appendTo("body");
    var lineNum = $textarea[0].scrollHeight / 50;

    if (window.devicePixelRatio && window.devicePixelRatio !== 1)
    {//存在页面缩放时，计算可能有偏差

    }

    $textarea.remove();

    return Math.ceil(lineNum);
};

Z.drag = function(elem, param, callback, $this)
{//拖拽或滑动
    if (Z.T.isString(elem))
        elem = Z.D.id(elem);

    if (!elem || !elem.nodeType)
    {//不支持拖拽
        return null;
    }

    if (Z.T.isString(param))
    {//如果参数是字符串，表示是拖拽对象
        param = {drag:Z.D.id(param)};
    }
    else if (param.nodeType)
    {
        param = {drag:param};
    }

    return new Z.Draggable({immediate:true, elem:elem, param:param, callback:callback, callthis:$this});
};

Z.dragInParent = function(elem, drag, parent, callback, $this)
{//拖拽或滑动
    if (Z.T.isString(elem))
        elem = Z.D.id(elem);

    if (!elem || !elem.nodeType)
    {//不支持拖拽
        return null;
    }

    if (Z.T.isString(drag))
        drag = Z.D.id(drag);

    if (!drag || !drag.nodeType)
    {//不支持拖拽
        return null;
    }

    if (Z.T.isString(parent))
        parent = Z.D.id(parent);

    if (!parent || !parent.nodeType)
    {//不支持拖拽
        return null;
    }

    //控制右边和下边不超线
    var width = parent.offsetWidth - elem.offsetWidth;
    var height = parent.offsetHeight - elem.offsetHeight;

    var param = {drag: drag, left: parent.offsetLeft, top: parent.offsetTop, width: width, height: height};
    return new Z.Draggable({immediate:true, elem:elem, param:param, callback:callback, callthis:$this});
};

Z.$elem = function(elem, clazz)
{//获取元素的对象封装
    if (elem instanceof Z.Query)
    {//传入的是Z.Query
        if (elem[0])
            return elem;
    }
    else if (Z.T.isElement(elem) || Z.T.isWindow(elem) || Z.T.isDocument(elem))
    {//如果传入了元素/窗体/文档，则取元素
        return Z(elem);
    }
    else if (Z.T.isString(elem))
    {//如果传入的是字符串
        if (Z(elem)[0])
            return Z(elem);
        if (!/^#/.test(elem) && Z("#" + elem)[0])
            return Z("#"+elem);
    }

    if (clazz)
    {//如果传入了类名，则统一弹出告警
        Z.alert("["+clazz+"]的[elem]参数必须是元素对象或元素编号");
        throw "elem does not exist";
    }
    return Z("");
};

Z.$selector = function(selector, target)
{//指定目标查找
    return target == null?Z(selector):Z.$elem(target).find(selector);
};

Z.$cover = function($elem)
{//在元素后面增加一个封套，然后再把元素放置到封套里面
    $elem = Z.$elem($elem);

    //1.如果父节点是封套，直接返回封套
    var $parent = $elem.parent();
    if ($parent.length > 0 && $parent[0].tagName.toLowerCase() == "zcover")
        return $parent;

    //2.创建封套
    var $cover = Z("<zcover></zcover>").insertAfter($elem)
                    .cssMaybe("float", $elem.css("float"))
                    .cssMaybe("margin-left", $elem.css("marginLeft"))
                    .cssMaybe("margin-right", $elem.css("marginRight"))
                    .cssMaybe("margin-top", $elem.css("marginTop"))
                    .cssMaybe("margin-bottom", $elem.css("marginBottom"));

    if ($elem.css("width").indexOf("%") != -1)
    {//要求百分比的，必须使用style中定义，否则不支持
        $cover.cssMaybe("width", $elem.css("width"));
        $elem.css("width", "100%");
    }

    $elem.appendTo($cover).css("margin", 0);
    return $cover;
};

/**************************************************/
//定义正则表达式常量
/**************************************************/
Z.R = Z.Regexps =
{
    //空格
    SPACE                       : /\s+/,
    SPACE_LEFT                  : /^\s+/,
    SPACE_RIGHT                 : /\s+$/,

    //数字相关
    NUMERIC                     : /^\d+$/,//数字，至少1位
    INTEGER                     : /^(0|[\+\-]?[1-9]\d*)$/,//整数，支持正负数
    INTEGER_P                   : /^[1-9]\d*$/,//正整数，第一个数字是1-9
    INTEGER_N_N                 : /^(0|[1-9]\d*)$/,//非负整数，0或者正整数

    FLOAT                       : /^(0|[\+\-]?[1-9]\d*)(\.\d+)?$/,//浮点值，支持多位小数点，支持正负数
    FLOAT_N_N                   : /^(0|[1-9]\d*)(\.\d+)?$/,//浮点值，支持多位小数

    AMOUNT_2R                   : /^(0|[\+\-]?[1-9]\d*)(\.\d{1,2})?$/,//标准元金额，支持0-2位小数，支持正负数
    AMOUNT_2R_FIXED             : /^(0|[\+\-]?[1-9]\d*)(\.\d{2})$/,//固定元金额，两位小数，支持正负数
    AMOUNT_N_N_2R               : /^(0|[1-9]\d*)(\.\d{1,2})?$/,//标准元金额，支持0-2位小数
    AMOUNT_N_N_2R_FIXED         : /^(0|[1-9]\d*)(\.\d{2})$/,//固定元金额，两位小数

    //字符相关
    ALPHABAT                    : /^[A-Za-z]+$/,//字母
    ALPHABAT_UPPER              : /^[A-Z]+$/,//大写字母
    ALPHABAT_LOWER              : /^[a-z]+$/,//小写字母

    ALPHA_LOWER_NUMERIC         : /^[a-z0-9]+$/,//小写字母或数字
    ALPHA_UPPER_NUMERIC         : /^[A-Z0-9]+$/,//大写字母或数字

    ALPHA_NUMERIC               : /^[A-Za-z0-9]+$/,//大写小字母和数字
    ALPHA_NUMERIC_PA            : /^[A-Za-z][A-Za-z0-9]*$/,//大写小字母和数字，字母开头

    ALPHABAT_DOUBLE             : /^[^x00-xff]+$/,//双字节
    CHINESE                     : /^[\u4e00-\u9fa5]+$/,//中文
    CHINESE_ALPHA_NUMERIC       : /^[\u4e00-\u9fa5A-Za-z0-9]+$/,//中文大小写字母和数字

    //日期
    DATE                        : /^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))$/,
    TIME                        : /^([0-1][0-9]|[2][0-3]):([0-5][0-9]):([0-5][0-9])$/,
    DATE_TIME                   : /^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\s(([0-1][0-9]|[2][0-3]):([0-5][0-9]):([0-5][0-9]))$/,
    DATE_TIME_MATCH             : /^(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})$/,

    //HTML
    HTML                        : /<|&#?\w+;/,
    HTML_TAG                    : /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
    HTML_TAG_NAME               : /<([\w:]+)/,

    //需求表达式
    ACCOUNT                     : /^(?!(_|@|\.))(?!.*?(_|@|\.)$)[\w@\.\u4e00-\u9fa5]{5,25}$/,//账号要求,中文大小写字母和数字和下划线、邮件符、点号，并且不能以@._开头和结尾
    PASSWORD                    : /^[\w@\.#$!~%]{6,16}$/,//密码要求6-16位的大小写字母和.@_#$!~%符号

    MOBILE                      : /^((\+86)|(86)|)?(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|170|18[0|1|2|3|5|6|7|8|9])\d{8}$/,
    MOBILE_11                   : /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|170|18[0|1|2|3|5|6|7|8|9])\d{8}$/,
    IP                          : /^((?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])$/,
    MAC                         : /^[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}$/,
    QQ                          : /^[1-9]\d{4,10}$/,
    POSTAL_CODE                 : /^[1-9]\d{5}$/,
    EMAIL                       : /^([\w-_]+(?:\.[\w-_]+)*)@((?:[a-z0-9]+(?:-[a-zA-Z0-9]+)*)+\.[a-z]{2,6})$/,

    IDCARD                      : /^(\d{6})((((19|20)[0-9]{2})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))(\d{3}[0-9xX*])$/
};

/********************************************************************/
//定义类结构生成类，新类从Z.Class.newInstance()派生
//新类可选包含defaults属性和instance函数，支持arguments是一个{}对象
//通过new新建实例时拷贝defaults和arguments到实例的属性中，再调用instance初始化
/********************************************************************/
Z.C = Z.Class =
{
    newInstance: function()
    {
        return function()
        {
            //定义不立即执行属性和设置参数方法
            this.immediate = false;
            this.set = function(name, value){this[name] = value};


            //拷贝缺省属性和构造函数的参数，执行初始化函数，如果参数要求立即执行则调用执行方法
            Z.C.copyFields(this, this.defaults);
            Z.C.copyFields(this, arguments);
            if (this.init){this.init.apply(this);};
            if (this.immediate && this.execute){this.execute.apply(this);};
        }
    },
    copyFields: function(target, obj)
    {
        if (!target || !obj)
            return;

        if (Z.T.isLikeArray(obj))
        {//如果是类数组
            for (var i=0;i<obj.length;i++){
                for (var name in obj[i]){
                    target[name] = Z.clone(obj[i][name]);
                }
            }
        }
        else
        {
            for (var key in obj){
                target[key] = Z.clone(obj[key]);
            }
        }
    }
};

/**************************************************/
//文档加载完成判断的加载器
/**************************************************/
Z.Loader = Z.Class.newInstance();
Z.Loader.prototype =
{
    defaults:
    {
        isLoad: false,
        isInitialize: false,
        functions: [],
        parameters: []
    },

    init: function()
    {
        if (this.isInitialize)
            return;

        this.isInitialize = true;
        if (document.readyState === "complete")
        {
            this.completed();
            return;
        }

        Z.E.add(document, "DOMContentLoaded", this.completed, this);
        Z.E.add(window, "load", this.completed, this);
    },

    push: function(f, a)
    {
        var len = this.functions.length;
        this.functions[len] = f;
        this.parameters[len] = a;
    },
    completed: function()
    {
        if (this.isLoad)
            return;

        this.isLoad = true;
        if (!this.functions)
            return;

        for (var i=0;i<this.functions.length;i++)
            this.functions[i].apply(document, this.parameters[i]);

        this.functions = null;
        this.parameters = null;

        Z.E.remove(document, "DOMContentLoaded", this.completed, this);
        Z.E.remove(window, "load", this.completed, this);
    }
};

/**************************************************/
//哈唏表类
/**************************************************/
Z.HashMap = Z.Class.newInstance();
Z.HashMap.prototype =
{
    defaults:
    {
        _keys: [],
        _values: []
    },

    size: function()
    {
        return this._keys.length;
    },
    isEmpty: function()
    {
        return this._keys.length == 0;
    },
    containsKey: function(key)
    {
        return Z.AR.indexOf(this._keys, key) != -1;
    },
    containsValue: function(value)
    {
        return Z.AR.indexOf(this._values, value) != -1;
    },
    put: function(key, value)
    {
        var ind = Z.AR.indexOf(this._keys, key);
        if (ind != -1)
            this._values[ind] = value;
        else
        {
            var len = this._keys.length;
            this._keys[len] = key;
            this._values[len] = value;
        }
    },
    get: function(key)
    {
        var ind = Z.AR.indexOf(this._keys, key);
        if (ind == -1)
            return null;
        else
            return this._values[ind];
    },
    remove: function(key)
    {
        var ind = Z.AR.indexOf(this._keys, key);
        if (ind == -1)
            return;

        this._keys.splice(ind, 1);
        this._values.splice(ind, 1);
    },
    keySet: function()
    {
        return this._keys;
    },
    values: function()
    {
        return this._values;
    },
    clear: function()
    {
        this._keys.length = 0
        this._values.length = 0;
    },
    oString: function()
    {
        return "Z.HashMap";
    }
};

/**************************************************************/
//可拖动类，构造函数时传入拖拽对象和拖拽对象内允许的子对象和回调函数
/**************************************************************/
Z.Draggable = Z.Class.newInstance();
Z.Draggable.prototype =
{
    defaults:
    {
        elem: null,//拖拽对象
        param: null,//拖拽参数，支持left,top,right,bottom,width,height其中right,bottom时width,height无效
        drag: null,//拖拽对象中允许拖拽的子对象
        cursor: "move",//拖拽手势
        callback: null,//拖拽回调函数
        callthis: null,
        startX: 0,
        startY: 0,
        dragging: false
    },

    execute:function()
    {//执行
        if (!this.elem || !this.elem.nodeType)
        {
            alert("[Z.Draggable]没有指定拖拽对象或拖拽对象不支持");
            return;
        }

        if (this.param)
        {//指定拖拽范围
            this.drag = this.param.drag || this.elem;
            this.cursor = this.param.cursor || "move";

            if ("left" in this.param)
                this.left = this.param.left;
            if ("top" in this.param)
                this.top = this.param.top;
            if ("right" in this.param)
                this.right = this.param.right;
            else if ("left" in this && "width" in this.param)
                this.right = this.left + this.param.width;
            if ("bottom" in this.param)
                this.bottom = this.param.bottom;
            else if ("top" in this && "height" in this.param)
                this.bottom = this.top + this.param.height;
        }

        //定义鼠标样式和按下开始拖拽事情
        Z(this.drag).css("cursor", this.cursor).mousedown(this.doStartDrag, this);
    },
    close: function()
    {//关闭
        Z(this.drag).offmousedown(this.doStartDrag, this);
    },

    doStartDrag:function(e)
    {//开始拖拽
        this.buttons = e.buttons;
        this.startX = Z.E.clientX(e) - Z(this.elem).offsetLeft() + parseInt(Z(this.elem).css('marginLeft'));
        this.startY = Z.E.clientY(e) - Z(this.elem).offsetTop() + parseInt(Z(this.elem).css('marginTop'));

        Z(document).mousemove(this.doDragging, this).mouseup(this.doStopDrag, this);

        if (Z.T.isFunction(this.callback)){//回调
               this.callback.call(this.callthis || this, e, this.dragging);
           }
    },

    doDragging:function(e)
    {//拖拽中
        Z.E.cancel(e);
        if (!e.buttons || e.buttons !== this.buttons)
            return this.doStopDrag.call(this, e);

        var offsetLeft = Z.E.clientX(e) - this.startX;
        var offsetTop = Z.E.clientY(e) - this.startY;

        if (this.param)
        {
            if ("left" in this && offsetLeft < this.left)
                offsetLeft = this.left;
            if ("right" in this && offsetLeft > this.right)
                offsetLeft = this.right;
            if ("top" in this && offsetTop < this.top)
                offsetTop = this.top;
            if ("bottom" in this && offsetTop > this.bottom)
                offsetTop = this.bottom;
        }

        if (Z.T.isFunction(this.callback)){//回调
            this.callback.call(this.callthis || this, e, this.dragging);
        }
        Z(this.elem).css({left:offsetLeft, top:offsetTop});
        Z.D.clearSelection();
    },

    doStopDrag:function(e)
    {//停止拖拽
        Z(document).offmousemove(this.doDragging, this).offmouseup(this.doStopDrag, this);

        if (Z.T.isFunction(this.callback))
        {//回调
            this.callback.call(this.callthis || this, e, this.dragging);
        }
    }
};

//END
})(window);
